(function () {
    //注意:不要在第一行添加注释或空行，避免$.Import失败！
    
    //ID生成器
    var IDMaker = function () {
        return {
            id: 0,
            New: function () {
                return ++this.id;
            }
        }
    };
	return {
		//创建一个richedit
		create: function (cfg,editor, owner) {
			return {
				/*
				编辑器的配置
				cfg:{
					fnSave:function(owner,fnOK,fnFail){},//保存编辑的内容
					fnUploadFile:function(file,fnOK,fnFail){},//上传文件 fnOK(path)  fnFail(err)
                    fnGetCompiler:function(type){},//得到控件的编译器
                    fnTemplate:function(entity){},//得到控件的模板
					autoSaveInterval:0,//自动保存的间隔时间，单位为秒，为0表示不支持自动保存
				}
				* */
				cfg: cfg,//编辑器配置

				/*
				编辑器操作接口
					getUrl:function(){},//得到editor视图对应的url
					refresh:function(){},//更新界面(只更新操作区)
					refreshAll:function(){},//更新所有界面
					setFullScreen:function(bFull){},//切换全屏显示
					getFullScreen:function(){},//判断是否在全屏状态
					fnFocusChange:function(focus){}
				* */
				editor: editor,//编辑器操作接口

				/*
				控件操作接口，由控件实例自动维护，如：
				controlActions[ entity.id ] = editAction;
				控件操作接口至少要提供：
					refresh:function(bRecure){},//更新实例显示
				* */
				controlActions: {},

				/*
				* 画布操作接口
				* 至少提供函数：
				* refresh:function(){} //更新界面
				* */
				canvas: null,

				/*
				* 工具栏操作接口
				* 至少提供函数：
				* refresh:function(){} //更新界面
				* */
				toolbar: null,

				/*
				* 控件实例对应的dom对象，由控件实例自动维护
				* 如：doms[ entity.id ] = entityDom
				* */
				doms: {},

				//所有当前选中的实例
				selected: [],

				//当前焦点实例
				focus: null,

				//修改标志
				isModified : false,

				/*
				虚拟的根控件实例
				示例：
				owner:{
					id:0,
                    key:"",
                    isContainer:true,
					value:{},
					children:[],//所有的实例[{id:0,name:"",value:{},children:[]},...]
				},
				* */
				owner: owner,

				//id生成器
				idmaker: IDMaker(),

				//======= 基本的实例操作(entity类扩展) [begin] ============================
				getID: function (entity) {
					if( !entity ) return -1;
					return entity.id;
				},
				setID: function (entity, id) {
					entity.id = id;
				},

				getType: function (entity) {
					return entity.key;
				},
				setType: function (entity, type) {
					entity.key = type;
				},

				

				getChildren: function (entity) {
					return entity.children || [];
				},
				isContainer: function (entity) {
                    return entity.isContainer;
				},

				getProp: function (entity, path) {
					var me = this;
					return $.getValue(entity.value, path);
				},
				setProp: function (entity, path, val) {
					var me = this;
					$.setValue(entity.value, path, val);
					me.refreshEntity(entity);

					me.isModified = true;
				},

				refreshEntity:function(entity){
					var me = this;
					var act = me.getAction(entity);
					if( act ) act.refresh(true);
				},
				isFocus:function(entity){
					var me = this;
					return me.focus && entity && (entity === me.focus || me.getID(entity) ===me.getID(me.focus));
				},

				//======= 基本的实例操作(entity类扩展) [end] ============================

				//========== 查找与关系判断 [begin] =================================
				getIndex: function (entity, parent) {
					var me = this;
					if (!parent) parent = me.owner;
					return $.indexOfArray(entity, parent.children, function (a, b) {
						return me.getID(a) === me.getID(b)
					});
				},

				//根据id查找实例
				// from可选 不传时代表从owner开始找起
				find: function (id, from) {
					var me = this;
					var found = null;
					if (!from) from = me.owner;
					var children = me.getChildren(from);

					var index = $.indexOfArray(id, children, function (a, b) {
						return a === me.getID(b)
					});
					if (index >= 0) found = children[index];
					else {
						$.each(children, function (a) {
							found = me.find(id, a);
							if (found) return true;
						})
					}
					return found;
				},

				//查找父实例
				// from可选 不传时代表从owner开始找起
				getParent: function (entity, from) {
					var me = this;
					var found = null;
					if (!from) from = me.owner;
					var index = me.getIndex(entity, from);
					if (index >= 0) found = from;
					else {
						$.each(me.getChildren(from), function (e) {
							found = me.getParent(entity, e);
							if (found) return true;
						});
					}
					return found;
				},
				//判断是否为它的后代
				descendantOf: function (descendant, parent) {
					var me = this;
					var children = me.getChildren(parent);
					var count = children.length;
					var id = me.getID(descendant);
					for (var i = 0; i < count; i++) {
						var e = children[i];
						if (me.descendantOf(descendant, e)) return true;
						if (id === me.getID(e)) return true;
					}
					return false;
				},
				//========== 查找与关系判断 [end] =================================

				//========== 实例的生命周期 [begin] =================================
				createID: function () {
                    return this.idmaker.New();
				},
				//根据类型创建新的控件实例
				createEntity: function (define,parent,index) {
					var me = this;
					var entity = {};
					me.setID(entity, me.createID());
                    me.setType(entity, define.key);

                    entity.isContainer = define.isContainer;

					entity.value = {};
                    entity.children = [];

                    var compiler = me.cfg.fnGetCompiler(define.key);
                    compiler.initControl(entity);

					if( parent ){
						var children = me.getChildren(parent);
						if( index ){
							index = $.toInt(index);
							if( index < 0 || index > children.length-1 ) {
								
								children.push(entity);
							}
							else {
								
								children.splice(index,0,entity);
							}
						}else{
							
							children.push(entity);
						}
						me.refreshEntity(parent);
					}
					me.isModified = true;
					if( me.toolbar ) me.toolbar.refresh();
					return entity;
				},
				//删除实例
				removeEntity: function (entity) {
					var me = this;
					if( !entity ) return;
					var id = me.getID(entity);

					me.unselect(entity);
					var parent = me.getParent(entity);
					var index = me.getIndex(entity, parent);
					var children = me.getChildren(parent);
					children.splice(index, 1);
					if( id in me.controlActions ) delete me.controlActions[id];
					

					me.isModified = true;
					if( me.toolbar ) me.toolbar.refresh();
				},
				//删除所有选中的实例
				removeAllSelected:function(){
					var me = this;
					$.each(me.selected,function (e) {
						me.removeEntity(e)
					});
					me.selected=[];
					me.focus=null;
					me.isModified = true;
					me.editor.fnFocusChange(me.focus);
				},
				//格式化实例
				format: function (entity) {
					var me = this;
					me.setID(entity, me.createID());
					$.each(me.getChildren(entity), function (e) {
						me.format(e);
					});
				},
				//得到实例的模板
				getTemplate:function(entity){
					var me = this;
					var tmp="";
					var key = me.getType(entity);
					if( $.isFunction(me.cfg.fnTemplate)) tmp = me.cfg.fnTemplate(entity);
					if( tmp ) return tmp;
					if( $.isFunction(me.cfg.fnTemplate)){
						tmp = me.cfg.fnTemplate(key,entity);
						if( tmp ) return tmp;
					}

					return "template/"+key;
                },
                serial: function () {
                    
                },
                unserial: function () {
                    
                },
				//========== 实例的生命周期 [end] =================================

				//========== 实例的选择 [begin] =================================
				_setFocus:function(entity){
					var me = this;
					if( me.focus !== entity ){
						me.focus = entity;
						me.editor.fnFocusChange(me.focus);
					}
				},
				//选中
				select: function (entity) {
					this.selected.push(entity);
					this._setFocus(entity);
				},
				//取消选中
				unselect: function (entity) {
					var me = this;
					var isFocus = me.isFocus(entity);

					var index = $.indexOfArray(entity, me.selected, function (a, b) {
						return me.getID(a) === me.getID(b)
					});
					if (index >= 0) {
						me.selected.splice(index, 1);
						if( isFocus ){
							if (me.selected.length > 0 ) {
								this._setFocus(me.selected[0]);
							}
						}
					}
				},
				//清空选择
				clearSelect: function () {
					this.selected = [];
					this._setFocus(null);
				},
				//选中下一个
				selectNext: function (entity) {
					var me = this;
					var parent = me.getParent(entity);
					var index = me.getIndex(entity, parent);
					var children = me.getChildren(parent);
					var next = (index >= children.length - 1 ? children[0] : children[index + 1]);
					me.selected.push(next);
					me._setFocus(next);

				},
				//选中上一个
				selectPrev: function (entity) {
					var me = this;
					var parent = me.getParent(entity);
					var index = me.getIndex(entity, parent);
					var children = me.getChildren(parent);
					var prev = (index > 0 ? children[index - 1] : children[children.length - 1]);
					me.selected.push(prev);
					me._setFocus(prev);
				},
				//选择上一级
				selectUp: function (entity) {
					var me = this;
					var parent = me.getParent(entity);
					me.selected.push(parent);
					me._setFocus(parent);
				},
				//选择下一级
				selectDown: function (entity) {
					var me = this;
					if (me.isContainer(entity)) {
						var children = me.getChildren(entity);
						if (children.length > 0) {
							me.selected.push(children[0]);
							me._setFocus(children[0]);
						}
					}
				},

				//根据落点计算元素
				hitTest: function (x, y, from) {
					var me = this;
					if (!from) from = me.owner;

					var dom = me.getDom(from);
					if (!dom) return null;
					var oNode = dom.node();

					var children = me.getChildren(from);

					//$.log("== hitTest from:"+from.id);
					var r = oNode.getBoundingClientRect();

					var left = r.left;
					var top = r.top;
					var width = r.width;
					var height = r.height;
					//$.log("hitTesting   x="+x+" y="+y+" left="+left+" top="+top+" width="+width+" height="+height);

					if (from === me.owner || (x >= left && x <= left + width && y >= top && y <= top + height)) {
						//落在from元素内，继续判断子元素
						var len = children.length;
						for (var i = 0; i < len; i++) {
							var entity = children[i];
							var p = me.hitTest(x, y, entity);
							if (p) return p;
						}
						return from === me.owner ? null : from;
					} else return null;
				},
				//测试离哪个元素最近
				testPos: function (container, x, y) {
					var me = this;
					var ret = {entity: null, isBefore: false};
					var posInfos = [];
					var children = me.getChildren(container);
					$.each(children, function (entity) {
						var oNode = me.getDom(me.getID(entity)).node();

						//$.log("== hitTest from:"+from.id);
						var r = oNode.getBoundingClientRect();
						var left = r.left;
						var top = r.top;
						var width = r.width;
						var height = r.height;

						var obj = {
							entity: entity,
							delta: 9999999,
							side: ""
						};
						if (x < left) {
							if (left - x < obj.delta) {
								obj.delta = left - x;
								obj.side = "left";
							}
						}
						if (y < top) {
							if (top - y < obj.delta) {
								obj.delta = top - y;
								obj.side = "top";
							}
						}
						if (x > left + width) {
							if (x - (left + width) < obj.delta) {
								obj.delta = x - (left + width);
								obj.side = "right";
							}
						}
						if (y > top + height) {
							if (y - (top + height) < obj.delta) {
								obj.delta = y - (top + height);
								obj.side = "bottom";
							}
						}
						posInfos.push(obj);
					});
					//找出值最小的那一个
					var delta = 999999;
					var found = -1;
					$.each(posInfos, function (pos, index) {
						if (pos.delta < delta) {
							found = index;
							delta = pos.delta;
						}
					});
					return posInfos[found];
				},
				//========== 实例的选择 [end] =================================

				//============ 实例的移动 [begin] ======================
				moveUp: function (entity) {
					var me = this;
					var parent = me.getParent(entity);
					var index = me.getIndex(entity, parent);
					var children = me.getChildren(parent);
					children.splice(index, 1);
					var newIndex = index-1;

					if (newIndex < 0) {
						newIndex = children.length;
						children.push(entity);
					}
					else children.splice(newIndex, 0, entity);
					
					me.isModified = true;
				},
				moveDown: function (entity) {
					var me = this;

					var parent = me.getParent(entity);
					var index = me.getIndex(entity, parent);
					var children = me.getChildren(parent);
					if (index >= children.length - 1) {
						children.splice(index, 1);
						children.splice(0, 0, entity);
						
					} else {
						children.splice(index, 1);
						if (index + 1 > children.length - 1) {
							
							children.push(entity);
						}
						else {
							
							children.splice(index + 1, 0, entity);
						}
					}
					me.isModified = true;
				},
				moveIn: function (entity) {
					var me = this;

                    
                    var parent = me.getParent(entity);
                    
					if (parent) {
						var index = me.getIndex(entity, parent);
						var children = me.getChildren(parent);
						var next = null;
						if (index < children.length - 1) next = children[index + 1];
						if (!next || !me.isContainer(next)) {
							if (index > 0) next = children[index - 1];
						}
						if (next && me.isContainer(next)) {
							children.splice(index, 1);
							var nextChildren = me.getChildren(next);
							nextChildren.push(entity);
							
						}
					}
					me.isModified = true;
                },
                moveInOther: function (entity,parent) {
                    var me = this;
                    
                    if (entity !== parent && !me.descendantOf(entity, parent)) {
                        var oldParent = me.getParent(entity);
                        var index = me.getIndex(entity, oldParent);
                        oldParent.children.splice(index, 1);

                        var children = me.getChildren(parent);
                        children.push(entity);
                        
                        me.isModified = true;
                    }
				},
				moveOut: function (entity) {
					var me = this;
					var parent = me.getParent(entity);
					if (parent && parent !== me.owner) {
						var index = me.getIndex(entity, parent);

						var parent2 = me.getParent(parent);
						if (parent2) {
							var index2 = me.getIndex(parent, parent2);

							var children = me.getChildren(parent);
							var children2 = me.getChildren(parent2);
							children.splice(index, 1);
							children2.splice(index2, 0, entity);

							
						}
					}
					me.isModified = true;
				},
				moveTo: function (entity, target, isBefore) {
					var me = this;
					if (!me.descendantOf(entity, target)) {
						var targetParent = me.getParent(target);
						var targetIndex = me.getIndex(target, targetParent);
						var tpChildren = me.getChildren(targetParent);

						var parent = me.getParent(entity);
						var index = me.getIndex(entity, parent);
						me.getChildren(parent).splice(index, 1);
						if (isBefore) {
							tpChildren.splice(targetIndex, 0, entity);
							
						} else {
							if (targetIndex < tpChildren.length - 1) {
								
								tpChildren.splice(targetIndex + 1, 0, entity);
							} else {
								
								tpChildren.push(entity);
							}
						}
					}
					me.isModified = true;
				},
				//============ 实例的移动 [end] ======================

				//============= 接口安装 [begin] =======================
				setDom: function (entity, dom) {
					this.doms[this.getID(entity)] = dom;
				},
				getDom: function (entity) {
					var id = this.getID(entity);
					if (id in this.doms) return this.doms[id];
					return null;
				},
				removeDom:function(entity){
					var me = this;
					var id = me.getID(entity);
					if( id in me.doms ) delete me.doms[id];
				},

				setAction: function (entity, action) {
					this.controlActions[this.getID(entity)] = action;
				},
				getAction: function (entity) {
					var id = this.getID(entity);
					if (id in this.controlActions) return this.controlActions[id];
					return null;
				},
				removeAction:function(entity){
					var id = this.getID(entity);
					if (id in this.controlActions) delete this.controlActions[id];
				},

				setCanvas: function (canvas) {
					this.canvas = canvas;
				},
				getCanvas: function () {
					return this.canvas;
				},

				setToolbar: function (tb) {
					this.toolbar = tb;
				},
				getToolbar: function () {
					return this.toolbar;
				},
				//============= 接口安装 [end] =======================

				
				//============ undo & redo [end] =================

				//================ UI交互操作接口(通用style相关) [begin] ==================
				uiChangeProp:function (path,newVal) {
					var me = this;
					if( me.focus ){
						$.each(me.selected,function (entity) {
							if( $.hasPath(entity.value,path) ){
								me.setProp(entity,path,newVal);
								me.refreshEntity(entity);
							}

						});
						if( $.hasPath(me.focus.value,path) ){
							me.setProp(me.focus,path,newVal);
							me.refreshEntity(me.focus);
						}
						me.isModified = true;
						if( me.toolbar ) me.toolbar.refresh();
					}
				},
				uiMoveUp:function(){
					var me = this;
					$.each(me.selected,function (entity) {
						me.moveUp(entity)
					});
					me.isModified = true;
					if( me.toolbar ) me.toolbar.refresh();
				},
				uiMoveDown:function(){
					var me = this;
					$.each(me.selected,function (entity) {
						me.moveDown(entity)
					});
					me.isModified = true;
					if( me.toolbar ) me.toolbar.refresh();
				},
				uiMoveIn:function(){
					var me = this;
					$.each(me.selected,function (entity) {
						me.moveIn(entity)
					});
					me.isModified = true;
					if( me.toolbar ) me.toolbar.refresh();
				},
				uiMoveOut:function(){
					var me = this;
					$.each(me.selected,function (entity) {
						me.moveOut(entity)
					});
					me.isModified = true;
					if( me.toolbar ) me.toolbar.refresh();
				},
				uiMoveTo:function(){
					var me = this;
					me.isModified = true;
					if( me.toolbar ) me.toolbar.refresh();
				},
				//================ UI交互操作接口(通用style相关) [end] ==================

				//================ richedit 基本操作 [begin] =============================
				getModified:function () {
					return this.isModified;
				},
                setModified: function (b) {
                    if (this.cfg.fnSaveImd) this.cfg.fnSaveImd();
                    else
					    this.isModified = b;
				},

				getFocus:function () {
					return this.focus;
				},

				getStyleGen:function () {
					return styleGen;
				}
				//================ richedit 基本操作 [end] =============================

			}
		}
	}
})();
